package cn.com.easy.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.NumberFormat;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
import com.jcraft.jsch.UserInfo;

/**
 * linux
 * 
 * @author nibili 2019年12月3日下午8:45:47
 * 
 */
public class SSHLinuxUtils {

	private String host;

	private String user;

	private String password;

	private int port;

	private Session session;

	/**
	 * 创建一个连接
	 * 
	 * @param host
	 *            地址
	 * @param user
	 *            用户名
	 * @param password
	 *            密码
	 * @param port
	 *            ssh2端口
	 */
	public SSHLinuxUtils(String host, String user, String password, int port) {
		this.host = host;
		this.user = user;
		this.password = password;
		this.port = port;
	}

	/**
	 * 初始化session
	 * 
	 * @throws Exception
	 * @auth nibili 2019年12月3日 下午11:24:37
	 */
	private void initialSession() throws Exception {
		if (session == null) {
			JSch jsch = new JSch();
			session = jsch.getSession(user, host, port);
			session.setUserInfo(new UserInfo() {

				public String getPassphrase() {
					return null;
				}

				public String getPassword() {
					return null;
				}

				public boolean promptPassword(String arg0) {
					return false;
				}

				public boolean promptPassphrase(String arg0) {
					return false;
				}

				public boolean promptYesNo(String arg0) {
					return true;
				}

				public void showMessage(String arg0) {
				}

			});
			session.setPassword(password);
			session.connect();
		}
	}

	/**
	 * 关闭连接
	 * 
	 * @throws Exception
	 */
	public void close() throws Exception {
		if (session != null && session.isConnected()) {
			session.disconnect();
			session = null;
		}
	}

	/**
	 * 上传文件
	 * 
	 * @param localPath
	 *            本地路径，若为空，表示当前路径
	 * @param localFile
	 *            本地文件名，若为空或是“*”，表示目前下全部文件
	 * @param remotePath
	 *            远程路径，若为空，表示当前路径，若服务器上无此目录，则会自动创建
	 * @throws Exception
	 */
	public void putFile(String localPath, String remotePath) throws Exception {
		this.initialSession();
		Channel channelSftp = session.openChannel("sftp");
		channelSftp.connect();
		ChannelSftp c = (ChannelSftp) channelSftp;
		if (remotePath != null && remotePath.trim().length() > 0) {
			this.runCommand("mkdir -p " + remotePath);
		} else {
		}

		if (localPath != null && localPath.trim().length() > 0) {
			File file = new File(localPath);
			if (file.isDirectory() == true) {

				List<String> fileList = EasyFileUtils.getFiles(file.getAbsolutePath());
				UploadMonitor monitor;
				File fileTemp;
				for (String filePath : fileList) {
					fileTemp = new File(filePath);
					monitor = new UploadMonitor(fileTemp.length());
					//
					String tempPath = remotePath + fileTemp.getParentFile().getAbsolutePath().replace(file.getAbsolutePath(), "").replaceAll("\\\\", "/");
					try {
						c.cd(tempPath);
					} catch (SftpException e) {
						// 创建目录
						this.runCommand("mkdir -p " + tempPath);
					}
					c.put(filePath, tempPath, monitor, ChannelSftp.OVERWRITE);
				}

			} else if (file.isFile() == true) {
				UploadMonitor monitor = new UploadMonitor(file.length());
				c.put(file.getAbsolutePath(), remotePath, monitor, ChannelSftp.OVERWRITE);
			}
		} else {
			throw new Exception("文件夹路径不能为空");
		}
		channelSftp.disconnect();
	}

	/**
	 * 运行命令
	 * 
	 * @param command
	 * @return
	 * @throws Exception
	 * @auth nibili 2019年12月3日 下午11:25:03
	 */
	public String runCommand(String command) throws Exception {
		// CommonUtil.printLogging("[" + command + "] begin", host, user);

		this.initialSession();
		InputStream in = null;
		InputStream err = null;
		BufferedReader inReader = null;
		BufferedReader errReader = null;
		int time = 0;
		String s = null;
		boolean run = false;
		StringBuffer sb = new StringBuffer();

		Channel channel = session.openChannel("exec");
		((ChannelExec) channel).setCommand(command);
		channel.setInputStream(null);
		((ChannelExec) channel).setErrStream(null);
		err = ((ChannelExec) channel).getErrStream();
		in = channel.getInputStream();
		channel.connect();
		inReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
		errReader = new BufferedReader(new InputStreamReader(err, "UTF-8"));

		while (true) {
			s = errReader.readLine();
			if (s != null) {
				sb.append("error:" + s).append("/n");
			} else {
				run = true;
				break;
			}
		}
		while (true) {
			s = inReader.readLine();
			if (s != null) {
				sb.append(s).append("/n");
			} else {
				run = true;
				break;
			}
		}

		while (true) {
			if (channel.isClosed() || run) {
				// CommonUtil.printLogging("[" + command + "] finish: " +
				// channel.getExitStatus(), host, user);
				break;
			}
			try {
				Thread.sleep(1000);
			} catch (Exception ee) {
			}
			if (time > 180) {
				// CommonUtil.printLogging("[" + command + "] finish2: " +
				// channel.getExitStatus(), host, user);
				break;
			}
			time++;
		}

		inReader.close();
		errReader.close();
		channel.disconnect();
		// session.disconnect();
		// System.out.println(sb.toString());
		return sb.toString();
	}

	/**
	 * 
	 * @param host
	 * @param user
	 * @param password
	 * @param port
	 * @param localPath
	 *            本地路径，为文件夹，则传文件夹
	 * @param remotePath
	 *            远程路径，若为空，表示当前路径，若服务器上无此目录，则会自动创建
	 * @throws Exception
	 * @auth nibili 2019年12月3日 下午11:27:40
	 */
	public static void putFile(String host, String user, String password, int port, String localPath, String remotePath) throws Exception {
		SSHLinuxUtils ssh2Util = new SSHLinuxUtils(host, user, password, 22);
		ssh2Util.putFile(localPath, remotePath);
		ssh2Util.close();
	}

	/**
	 * 运行命令
	 * 
	 * @param host
	 * @param user
	 * @param password
	 * @param port
	 * @param command
	 * @return
	 * @throws Exception
	 * @auth nibili 2019年12月3日 下午11:35:08
	 */
	public static String runCommand(String host, String user, String password, int port, String command) throws Exception {
		SSHLinuxUtils ssh2Util = new SSHLinuxUtils(host, user, password, 22);
		String temp = ssh2Util.runCommand(command);
		ssh2Util.close();
		return temp;
	}

	public static void main(String[] args) throws Exception {
		SSHLinuxUtils.putFile("192.168.1.105", "root", "root", 22, "E:/my_soft/git/easy-permision-platform_layui/easy-permision-platform_layui/target",
				"/home/projects/remoteDeployTest/easy-permision-platform_layui/deploy/target");
		String temp = SSHLinuxUtils.runCommand("192.168.1.105", "root", "root", 22, "ls /home");
		System.out.println(temp);
	}

	/**
	 * 
	 * @author nibili 2019年12月4日上午12:48:34
	 * 
	 */
	public class UploadMonitor implements SftpProgressMonitor, Runnable {

		/**
		 * 文件的总大小
		 */
		private long maxCount = 0;
		private long uploaded = 0;
		long startTime = 0L;

		private boolean isScheduled = false;

		private String src;

		ScheduledExecutorService executorService;

		public UploadMonitor(long maxCount) {
			this.maxCount = maxCount;
		}

		/**
		 * 当文件开始传输时，调用init方法
		 * 
		 * @param op
		 * @param src
		 * @param dest
		 * @param max
		 */
		@Override
		public void init(int op, String src, String dest, long max) {
			this.src = src;
			System.out.println("开始上传文件：" + src + "至远程：" + dest + "文件总大小:" + maxCount / 1024 + "KB");
			startTime = System.currentTimeMillis();
		}

		/**
		 * 当每次传输了一个数据块后，调用count方法，count方法的参数为这一次传输的数据块大小
		 * 
		 * @param count
		 * @return
		 */
		@Override
		public boolean count(long count) {
			if (!isScheduled) {
				createTread();
			}
			uploaded += count;
			// System.out.println("本次上传大小：" + count / 1024 + "KB,");
			if (count > 0) {
				return true;
			}
			return false;
		}

		/**
		 * 当传输结束时，调用end方法
		 */
		@Override
		public void end() {

		}

		/**
		 * 创建一个线程每隔一定时间，输出一下上传进度
		 */
		public void createTread() {
			executorService = Executors.newSingleThreadScheduledExecutor();

			// 1秒钟后开始执行，每2杪钟执行一次
			executorService.scheduleWithFixedDelay(this, 1, 1, TimeUnit.SECONDS);
			isScheduled = true;
		}

		@Override
		public void run() {
			NumberFormat format = NumberFormat.getPercentInstance();
			format.setMaximumFractionDigits(2);
			format.setMinimumFractionDigits(2);
			String value = format.format((uploaded / (double) maxCount));
			System.out.println("文件：" + this.src + ",总大小:" + maxCount / 1024 + "K,已传输：" + uploaded / 1024 + "KB,传输进度：" + value);
			if (uploaded == maxCount) {
				stop();
				long endTime = System.currentTimeMillis();
				System.out.println("文件：" + this.src + ",传输完成！用时：" + (endTime - startTime) / 1000 + "s");
			}
		}

		public void stop() {
			boolean isShutdown = executorService.isShutdown();
			if (!isShutdown) {
				executorService.shutdown();
			}

		}
	}

}
